package org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.habilidad;

import java.util.ArrayList;

import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.entrenador.Sugerencia;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.Futbolista;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.FutbolistaBase;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.Oponente;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.Balon;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.DespejeAlto;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PaseAlto;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionCampo;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionDespeje;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionFutura;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionBalon;

/**
 * @author Joan Crosas
 *
 */
public abstract class HabilidadConBalon implements Habilidad {
	protected Futbolista futbolista;
	protected int anticipacion;
	

	/**
	 * 
	 */
	public HabilidadConBalon( Futbolista futbolista ) {
		this.futbolista = futbolista;
		this.anticipacion = 0;
	}
	
	public HabilidadConBalon( Futbolista futbolista, int anticipacion ) {
		this.futbolista = futbolista;
		this.anticipacion = anticipacion;
	}
	
	protected Balon evaluarPase( Futbolista futbolistaDestino, double angulo, double potencia, double anguloVertical ) {
		return evaluarPase( futbolistaDestino, angulo, potencia, anguloVertical, false );
	}
	
	protected Balon evaluarPase( Futbolista futbolistaDestino, double angulo, double potencia, double anguloVertical, boolean retroceder ) {
		
		PosicionCampo posicionInicio = futbolista.getVisionPartido().getBalon().getPosicionBalon();
		double velocidadInicial = futbolista.getRemate() * potencia;	
		double anguloError1 = angulo + futbolista.getPrecision() / 2;
		double anguloError2 = angulo - futbolista.getPrecision() / 2;
		
		angulo = corregirAngulo( angulo );
		anguloError1 = corregirAngulo( anguloError1 );
		anguloError2 = corregirAngulo( anguloError2 );
		
		Balon b = new Balon( posicionInicio, angulo, velocidadInicial, anguloVertical );
		Balon b1 = new Balon( posicionInicio, anguloError1, velocidadInicial, anguloVertical );
		Balon b2 = new Balon( posicionInicio, anguloError2, velocidadInicial, anguloVertical );
		
		boolean autopase = futbolista == futbolistaDestino;
		
		PosicionFutura posFutura = futbolistaDestino.podreInterceptarPase( b, anticipacion, autopase );
		PosicionFutura posFutura1 = futbolistaDestino.podreInterceptarPase( b1, anticipacion, autopase );
		PosicionFutura posFutura2 = futbolistaDestino.podreInterceptarPase( b2, anticipacion, autopase );
		
		if( posFutura != null && posFutura1 != null && posFutura2 != null ) {

			int seguridadPase = (futbolista != futbolistaDestino)? 
					futbolistaDestino.getSeguridadPase():
					( retroceder? FutbolistaBase.SEGURIDAD_AUTOPASE+1: FutbolistaBase.SEGURIDAD_AUTOPASE );
			
			if( autopase && futbolista.isPortero() ) {
				seguridadPase = FutbolistaBase.SEGURIDAD_PASE_ALTA;
			}
			
			
			ArrayList<Oponente> oponentes = futbolista.getVisionPartido().getOponentes();
			for( int i = 0; i < oponentes.size(); i++ ) {
				PosicionFutura posFuturaOp = oponentes.get( i ).puedoInterceptarPase( b );
				PosicionFutura posFuturaOp1 = oponentes.get( i ).puedoInterceptarPase( b1 );
				PosicionFutura posFuturaOp2 = oponentes.get( i ).puedoInterceptarPase( b2 );
				
				if( posFuturaOp != null && !paseSeguro( seguridadPase, posFuturaOp, posFutura, posFutura1, posFutura2 ) ) {
					return null;
				}
				if( posFuturaOp1 != null && !paseSeguro( seguridadPase, posFuturaOp1, posFutura, posFutura1, posFutura2 ) ) {
					return null;
				}
				if( posFuturaOp2 != null && !paseSeguro( seguridadPase, posFuturaOp2, posFutura, posFutura1, posFutura2 ) ) {
					return null;
				}
			}
			
			// hacemos cumplir la distancia min pase de pase
			if( !autopase && anticipacion > 0 && futbolista.getPosicion().distancia( posFutura ) < FutbolistaBase.DISTANCIA_MIN_PASE ) {
				double dMin = FutbolistaBase.DISTANCIA_MIN_PASE - futbolista.getPosicion().distancia( posFutura );
				posFutura = posFutura.moverAngulo( angulo, dMin );
			}
			
			// prepara el comando i la sugerencia (si anticipacion > 0) preparo unicament la sugerencia (el comando ja el llan�ar� quan toqui)
			if( anticipacion == 0 ) {
				Comando comando = new ComandoGolpearBalon(futbolista.getIndice(), posFutura.toPosicion(), potencia, anguloVertical*180/Math.PI );
				Sugerencia sugerencia = new Sugerencia( Sugerencia.TipoSugerencia.RECIBIR_PASE );
				sugerencia.setFutbolista( futbolistaDestino );
				sugerencia.setPosicionDestino( posFutura.setDentroCampoJuego() );
				sugerencia.setTiempoValida( posFutura.getTiempo() + 2 );
				
				futbolista.getVisionPartido().addComando( comando );
				futbolista.getVisionPartido().addSugerencia( sugerencia );
				
			} else {
				Sugerencia sugerencia = new Sugerencia( Sugerencia.TipoSugerencia.CORRER );
				sugerencia.setFutbolista( futbolistaDestino );
				sugerencia.setPosicionDestino( posFutura.setDentroCampoJuego() );
				sugerencia.setTiempoValida( posFutura.getTiempo() + 2 + anticipacion );
				
				futbolista.getVisionPartido().addSugerencia( sugerencia );
			}
			
			
			// el pase es bueno
			return b;
		}
		
		return null;
	}
	
	protected Balon evaluarGol( double anguloBase, double anguloError1, double anguloError2, double potencia, double anguloVertical ) {
		PosicionCampo posicionInicio = futbolista.getVisionPartido().getBalon().getPosicionBalon();
		double velocidadInicial = futbolista.getRemate() * potencia;	
		anguloError1 = corregirAngulo( anguloError1 );
		anguloError2 = corregirAngulo( anguloError2 );
		
		Balon b1 = new Balon( posicionInicio, anguloError1, velocidadInicial, anguloVertical );
		Balon b2 = new Balon( posicionInicio, anguloError2, velocidadInicial, anguloVertical );
		
		if( b1.getPosicionEnLineaFondo() != null && b1.getPosicionEnLineaFondo().isCasiGol() 
				&& b2.getPosicionEnLineaFondo() != null && b2.getPosicionEnLineaFondo().isCasiGol() ) {
			
			ArrayList<Oponente> oponentes = futbolista.getVisionPartido().getOponentes();
			for( int i = 0; i < oponentes.size(); i++ ) {
				PosicionFutura posFuturaOp1 = oponentes.get( i ).puedoInterceptarPase( b1 );
				PosicionFutura posFuturaOp2 = oponentes.get( i ).puedoInterceptarPase( b2 );
				if( posFuturaOp1 != null || posFuturaOp2 != null ) {
					return null;
				}
			}
			
			Comando comando = new ComandoGolpearBalon(futbolista.getIndice(), anguloBase*180/Math.PI, potencia, anguloVertical*180/Math.PI );
			futbolista.getVisionPartido().addComando( comando );
			
			// el pase es/ser� bueno
			return b1;
			
		}
		
		return null;
	}
	
	protected DespejeAlto evaluarDespeje( double angulo, double potenciaDespeje, double anguloVerticalDespeje ) {
		double velocidadInicial = futbolista.getRemate() * potenciaDespeje;
		PosicionCampo posicionInicio = futbolista.getVisionPartido().getBalon().getPosicionBalon();
		double anguloPosteDerRival = posicionInicio.angulo( FutbolistaBase.POSICION_POSTE_DER_RIVAL );
		double anguloPosteIzqRival = posicionInicio.angulo( FutbolistaBase.POSICION_POSTE_IZQ_RIVAL );
		double anguloPosteDerPropia = posicionInicio.angulo( FutbolistaBase.POSICION_POSTE_DER );
		double anguloPosteIzqPropia = posicionInicio.angulo( FutbolistaBase.POSICION_POSTE_IZQ );
		
		
		Balon balon = new Balon( posicionInicio, angulo, velocidadInicial, anguloVerticalDespeje );
		DespejeAlto despejeAlto = new DespejeAlto();
		despejeAlto.setBalon( balon );
		despejeAlto.setAngulo( angulo );
		
		
		ArrayList<Futbolista> futbolistas = futbolista.getVisionPartido().getFutbolistas();
		for( int i = 0; i < futbolistas.size(); i++ ) {
			if( futbolista != futbolistas.get(i) ) {
				PosicionDespeje posicionIntercepcion = futbolistas.get(i).podreInterceptarDespeje( balon );
				if( despejeAlto.getPosicionMinFutbolista() == null ) {
					despejeAlto.setPosicionMinFutbolista( posicionIntercepcion );
					despejeAlto.setFutbolistaDestino( futbolistas.get(i) );
					
				} else if( !despejeAlto.getPosicionMinFutbolista().isBalonRecuperado() && !posicionIntercepcion.isBalonRecuperado() &&
						posicionIntercepcion.getTiempo() < despejeAlto.getPosicionMinFutbolista().getTiempo() ) {
					despejeAlto.setPosicionMinFutbolista( posicionIntercepcion );
					despejeAlto.setFutbolistaDestino( futbolistas.get(i) );
					
				} else if( despejeAlto.getPosicionMinFutbolista().isBalonRecuperado() && posicionIntercepcion.isBalonRecuperado() &&
						posicionIntercepcion.getTiempo() < despejeAlto.getPosicionMinFutbolista().getTiempo() ) {
					despejeAlto.setPosicionMinFutbolista( posicionIntercepcion );
					despejeAlto.setFutbolistaDestino( futbolistas.get(i) );
				}
			}
		}
		
		ArrayList<Oponente> oponentes = futbolista.getVisionPartido().getOponentes();
		for( int i = 0; i < oponentes.size(); i++ ) {
			PosicionDespeje posicionIntercepcion = oponentes.get(i).podreInterceptarDespeje( balon );
			
			if( despejeAlto.getPosicionMinOponente() == null ) {
				despejeAlto.setPosicionMinOponente( posicionIntercepcion );
				
			} else if( !despejeAlto.getPosicionMinOponente().isBalonRecuperado() && !posicionIntercepcion.isBalonRecuperado() &&
					posicionIntercepcion.getTiempo() < despejeAlto.getPosicionMinFutbolista().getTiempo() ) {
				despejeAlto.setPosicionMinOponente( posicionIntercepcion );
				
			} else if( despejeAlto.getPosicionMinOponente().isBalonRecuperado() && posicionIntercepcion.isBalonRecuperado() &&
					posicionIntercepcion.getTiempo() < despejeAlto.getPosicionMinFutbolista().getTiempo() ) {
				despejeAlto.setPosicionMinOponente( posicionIntercepcion );
			}
		}
		
		int puntuacion = 0;
		if( angulo >= anguloPosteDerRival && angulo <= anguloPosteIzqRival ) {
			puntuacion = 1; // punto extra
		}
		if( angulo <= anguloPosteDerPropia && angulo >= anguloPosteIzqPropia ) {
			puntuacion = -10; // mal fario
		}
		if( despejeAlto.getBalon().getPosicionRebote().isDentroAreaRival() ) {
			puntuacion += 1; // punto extra
		}
		if( despejeAlto.getBalon().getPosicionRebote().isDentroArea() ) {
			puntuacion += -2; // mal fario
		}
		if( despejeAlto.getPosicionMinFutbolista() != null ) {
			if( despejeAlto.getPosicionMinFutbolista().distancia( FutbolistaBase.POSICION_PORTERIA_RIVAL ) < 18 ) {
				puntuacion += 1; // punto extra
			}
			if( despejeAlto.getPosicionMinFutbolista().distancia( FutbolistaBase.POSICION_PORTERIA ) < FutbolistaBase.DISTANCIA_DEFENSIVA_CRITICA ) {
				puntuacion += -2; // mal fario
			}
		}
		if( despejeAlto.getPosicionMinFutbolista() != null && despejeAlto.getPosicionMinOponente() == null ) {
			puntuacion += 10;
		} 
		if( despejeAlto.getPosicionMinFutbolista() != null && despejeAlto.getPosicionMinOponente() != null ) {
			puntuacion += Math.min( despejeAlto.getPosicionMinFutbolista().getTiempo() - despejeAlto.getPosicionMinOponente().getTiempo(), 10 );
		}
		despejeAlto.setPuntuacion( puntuacion );
		
		return despejeAlto;
	}
	
	
	protected PosicionFutura evaluarExactitudJugadaMortal( Balon balon, double alturaJugada ) {
		double alturaAnterior = 0;
		
		for( int i = 1; i < 30; i++ ) {
			PosicionBalon posicionBalon = balon.getPosicionBalon( i );
			if( alturaAnterior >= alturaJugada && posicionBalon.getAltura() < alturaJugada ) {
				return new PosicionFutura( posicionBalon, i );
			}
			alturaAnterior = posicionBalon.getAltura();
		}
		return new PosicionFutura( balon.getPosicionBalon(), 1 );
	}
	
	protected boolean evaluarEfectividadJugadaMortal( PaseAlto paseJugada, PosicionCampo posicionJugada, double alturaJugada, double errorMax ) {
		double alturaAnterior = 0;
		ArrayList<Oponente> oponentes = futbolista.getVisionPartido().getOponentes();
		
		for( int i = 1; i < 30; i++ ) {
			PosicionBalon posicionBalon = paseJugada.getBalon().getPosicionBalon( i );
			if( i < 5 ) {
				for( int j = 0; j < oponentes.size(); j++ ) {
					if( oponentes.get(j).balonEncima( posicionBalon, i ) ) {
						return false;
					}
				}
			}
			if( alturaAnterior >= alturaJugada && posicionBalon.getAltura() <= alturaJugada ) {
				if( posicionBalon.distancia( posicionJugada ) < errorMax ) {
					return true;
				} else {
					return false;
				}
			}
			alturaAnterior = posicionBalon.getAltura();
		}
		
		return false;
	}
	
	protected double getMitad( double x, double min ) {
		return (x + min )/2;
	}
	
	protected double getMitadAlta( double x, double max ) {
		return x + ((max - x)/2);
	}
	
	protected double corregirAngulo( double angulo ) {
		angulo = angulo % (Math.PI * 2d);
        if (angulo >= Math.PI) {
        	angulo = angulo - 2d * Math.PI;
        }
        return angulo;
	}
	
	private boolean paseSeguro( int seguridadPase, PosicionFutura oponente, PosicionFutura futbolista, 
			PosicionFutura futbolistaError1, PosicionFutura futbolistaError2 ) {
				
		
		if( futbolista.getTiempo() + seguridadPase < oponente.getTiempo() &&
				 futbolistaError1.getTiempo() + seguridadPase < oponente.getTiempo() && 
				 futbolistaError2.getTiempo() + seguridadPase < oponente.getTiempo() ) {
				 	
			return true;
		}
		return false;	
	}

}
